using FluentValidation.AspNetCore;
using wt.wine.Application;
using wt.wine.Application.Common.Interfaces;
using wt.wine.Infrastructure;
using wt.wine.Infrastructure.Persistence;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System;
using Quartz;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WebAPI.Filters;
using wt.wine.Application.Job;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace WebAPI
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            //注册编码提供程序   尝试处理乱码问题  失败
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            services.AddHttpClient();
            services.AddApplication();
            services.AddInfrastructure(Configuration);
            services.AddMemoryCache();
            services.AddHttpContextAccessor();
            services.AddHealthChecks()
                    .AddDbContextCheck<ApplicationDbContext>();
            services.AddControllersWithViews(options =>
                options.Filters.Add<ApiExceptionFilterAttribute>())
                    .AddFluentValidation().AddJsonOptions(x => x.JsonSerializerOptions.Converters.Add(new DateTimeConverter()));
            // Customise default API behaviour
            services.Configure<ApiBehaviorOptions>(options =>
            {
                options.SuppressModelStateInvalidFilter = true;
            });

            //允许的域名
            services.AddCors(options =>
            {

                options.AddDefaultPolicy(builder =>
                {
                    builder.WithOrigins("https://*.123.com")
                                      .AllowCredentials()
                                      .AllowAnyHeader()
                                      .SetIsOriginAllowedToAllowWildcardSubdomains();
                });
            });


            var jwtConfig = Configuration.GetSection("Jwt");
            var a = jwtConfig.GetValue<string>("Secret");
            //生成密钥
            var symmetricKeyAsBase64 = jwtConfig.GetValue<string>("Secret");
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);

            //认证参数
            services.AddAuthentication("Bearer")
                .AddJwtBearer(o =>
                {
                    o.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuerSigningKey = true,//是否验证签名,不验证的画可以篡改数据，不安全
                        IssuerSigningKey = signingKey,//解密的密钥
                        ValidateIssuer = false,//是否验证发行人，就是验证载荷中的Iss是否对应ValidIssuer参数
                        //ValidIssuer = jwtConfig.GetValue<string>("Iss"),//发行人
                        ValidateAudience = false,//是否验证订阅人，就是验证载荷中的Aud是否对应ValidAudience参数
                        //ValidAudience = jwtConfig.GetValue<string>("Aud"),//订阅人
                        ValidateLifetime = true,//是否验证过期时间，过期了就拒绝访问
                        ClockSkew = TimeSpan.Zero,//这个是缓冲过期时间，也就是说，即使我们配置了过期时间，这里也要考虑进去，过期时间+缓冲，默认好像是7分钟，你可以直接设置为0
                        RequireExpirationTime = true,
                    };

                });


            //services.AddControllers();
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPI", Version = "v1" });

                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "wt.wine.Domain.xml"));//第二个参数true表示注释文件包含了控制器的注释
                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "wt.wine.Application.xml"));//第二个参数true表示注释文件包含了控制器的注释
                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "WebAPI.xml"));//第二个参数true表示注释文件包含了控制器的注释

                //定义JwtBearer认证方式二
                options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
                {
                    Description = "(JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}（注意两者之间是一个空格）)",
                    Name = "Authorization",//jwt默认的参数名称
                    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.ApiKey
                });

                //声明一个Scheme，注意下面的Id要和上面AddSecurityDefinition中的参数name一致
                var scheme = new OpenApiSecurityScheme()
                {
                    Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
                };
                //注册全局认证（所有的接口都可以使用认证）
                options.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                    [scheme] = new string[0]
                });
            });


            services.AddQuartz(q =>
            {
             q.UseMicrosoftDependencyInjectionJobFactory();

                q.ScheduleJob<OrderStateJob>(timer => timer.StartNow().WithCronSchedule("0 */2 * * * ?"));
            });
            services.AddQuartzHostedService(x => x.WaitForJobsToComplete = true);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();

            }
            app.UseSwagger();
            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPI v1"));
            app.UseRouting();
            app.UseCors();
            app.UseHealthChecks("/health");
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
    public class DateTimeConverter : JsonConverter<DateTime>
    {
        public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            return DateTime.Parse(reader.GetString());
        }

        public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss"));
        }
    }
}
